package org.weasel.unittests;

import java.util.ArrayList;

import junit.framework.TestCase;

import org.jdom.Element;
import org.weasel.business.Developer;
import org.weasel.business.Project;
import org.weasel.business.Settings;
import org.weasel.business.Utilities;
import org.weasel.data.XMLManager;

/***
 * This test class tests the SettingsManager and the Settings class because
 * they are closely related together.
 * @author Plack
 *
 */
public class SettingsTest extends TestCase {
	private XMLManager xmlMan;
	private Settings settings;
	
	//this field is needed to pass the id of a created element in order to delete
	//it afterwards
	private static String uniqueID; 

	@Override
	protected void setUp() throws Exception {
		super.setUp();
		ArrayList<Developer> developers = new ArrayList<Developer>();
		Developer d = new Developer(Utilities.createUniqueId(), "name", "mail", "position");
		developers.add(d);
		settings = new Settings("./testfolder/SettingsTest.xml");
		settings.addDeveloper(d);
		xmlMan = new XMLManager("./testfolder/SettingsTest.xml");
	}

	@Override
	protected void tearDown() throws Exception {
		super.tearDown();
		settings = null;
		xmlMan = null;
	}
	
	/***
	 * This test gets the company name which is stored in the settings.xml
	 * @throws Exception
	 */
	public void testGetCompanyName() throws Exception {
		String expectedName = "New Company";
		String actualName = settings.getCompanyName();
		
		assertEquals(expectedName, actualName);
	}

	/***
	 * This test updates the name of the company and then it uses the getCompanyName
	 * method to check if it was updated
	 * @throws Exception
	 */
	public void testCompanyName() throws Exception {
		String newCompanyName = "New Company";
		settings.setCompanyName(newCompanyName);
		
		String actualCompanyName = settings.getCompanyName();
		assertEquals("expected name: New Company", newCompanyName, actualCompanyName);
	}
	
	/***
	 * This test checks if the settingsmanager reads out projects correctly.
	 * It assumes the presence of 2 projects with the specified names.
	 * @throws Exception
	 */
	public void testGetProjects() throws Exception {
		ArrayList<Project> projects = settings.getProjects();
		Project project1 = projects.get(0);
		Project project2 = projects.get(1);
		
		assertEquals("expected: project name", "My first new project", project1.getName());
		assertEquals("expected: project name", "My second new project", project2.getName());
	}

	/***
	 * This test creates a new project entry in the xml file
	 * and then it checks if it is really there. It tests automatically the
	 * method addProject because createAndAddProject uses it.
	 * @throws Exception
	 */
	public void testCreateProject() throws Exception {
		String projectName = "New Project";
		String projectPath = "./testfolder/NewProject.xml";
		Project newProject = settings.createAndAddProject(projectName, projectPath);
		uniqueID = newProject.getId();
		
		xmlMan.reloadXMLDocument();
		Element projectElement = xmlMan.getElementByQuery("/descendant::project[id=\"" + newProject.getId() + "\"]");
		
		//the project element must not be null -> the project is in the xml file
		assertNotNull("The object cannot be null", projectElement);
		
		//the project file should exist
		assertTrue("The file should not exist", Utilities.existsFile(projectPath));
	}

	/***
	 * This test checks if a project is deleted.
	 * It deletes the project previously created in the testCreateProject().
	 * In order to do this it needs the id of that projects which gets from the static
	 * variable uniqueID.
	 * @throws Exception
	 */
	public void testDeleteProject() throws Exception {
		String projectName = "New Project";
		String projectPath = "./testfolder/NewProject.xml";
		//can take the list of developers here directly from the settings object since they are initialized
		//at set up
		Project projectToDelete = new Project(uniqueID, projectName, projectPath, settings.getDevelopers());
		xmlMan.reloadXMLDocument();
		Element projectElement = xmlMan.getElementByQuery("/descendant::project[id=\"" + projectToDelete.getId() + "\"]");
		
		//chechks the presence of the element in the file
		assertNotNull(projectElement);
		
		settings.removeProject(projectToDelete);
		
		//a reload has to be done because the document was modified by another xmlmanager
		xmlMan.reloadXMLDocument();
		projectElement = xmlMan.getElementByQuery("/descendant::project[id=\"" + projectToDelete.getId() + "\"]");
		
		//checks the absence of the element
		assertNull(projectElement);
		
		//and it should neither be in the list of projects
		assertFalse(settings.getProjects().contains(projectToDelete));
		
		//also the file of the project shouldn exist anymore
		assertFalse(Utilities.existsFile(projectPath));
	}
	
	/***
	 * This test checks if the developers are read in correctly.
	 * It assumes that there are 2 developers in the xml file which is used to test
	 * the settingsManager.
	 * @throws Exception
	 */
	public void testGetDevelopers() throws Exception {
		ArrayList<Developer> developers = settings.getDevelopers();
		Developer d1 = developers.get(0);
		Developer d2 = developers.get(1);
		
		assertEquals("expected: developer name of d1", "Matthias Braunhofer", d1.getName());
		assertEquals("expected: developer email of d1", "hallo@hotmail.com", d1.getEMail());
		assertEquals("expected: developer position of d1", "Top Manager", d1.getPosition());
		
		assertEquals("expected: developer name of d2", "Manfred Ramoser", d2.getName());
		assertEquals("expected: developer email of d2", "hallo@hotmail.com", d2.getEMail());
		assertEquals("expected: developer position of d2", "XP Programmer", d2.getPosition());
	}

	public void testCreateDeveloper() throws Exception {
		String name = "Hans Mustermann";
		String mail = "prof@unibz.it";
		String position = "Executive";
		Developer d = settings.createAndAddDeveloper(name, mail, position);
		uniqueID = d.getId();
		xmlMan.reloadXMLDocument();
		Element developer = xmlMan.getElementByQuery("/descendant::developer[id=\"" + uniqueID + "\"]");
		
		assertNotNull(developer);
		assertEquals("excpected: developer name", name, developer.getChild("name").getText());
		assertEquals("excpected: developer email", mail, developer.getChild("email").getText());
		assertEquals("excpected: developer position", position, developer.getChild("position").getText());
	}
	
	/***
	 * This method tests if a developer is correctly removed from the list and the xml file.
	 * @throws Exception
	 */
	public void testDeleteDeveloper() throws Exception {
		String name = "Hans Mustermann";
		String mail = "prof@unibz.it";
		String position = "Executive";
		String id = uniqueID;
		Developer developerToDelete = new Developer(id, name, mail, position);
		
		xmlMan.reloadXMLDocument();
		Element developer = xmlMan.getElementByQuery("/descendant::developer[id=\"" + uniqueID + "\"]");
		//the presence of the developer is checked
		assertNotNull(developer);
		
		settings.removeDeveloper(developerToDelete);
		
		xmlMan.reloadXMLDocument();
		developer = xmlMan.getElementByQuery("/descendant::developer[id=\"" + uniqueID + "\"]");
		
		//here the absence of the developer is checked
		assertNull(developer);
		assertFalse(settings.getDevelopers().contains(developerToDelete));
	}
}
